package de.preamp.clients.java.playlist;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;

/**
 * @author André Stannek
 * @version 2011-06-05
 */
public class PlaylistManagerInFileImpl implements PlaylistManager
{
    /**
     * 
     */
    private static final long serialVersionUID = -5159757278745619312L;

    /**
     * List holding all available Playlists.
     */
    private transient List<Playlist> playlists;

    /**
     * listeners.
     */
    private final transient Set<ListDataListener> listeners;

    /**
     * the name of the default playlists file.
     */
    private static final transient String PLAYLISTS_FILE = "playlists";

    /**
     * the currently selected index in this manager.
     */
    private transient int selectedIndex;

    /**
     * Default constructor trying to load the old playlists file or creating a
     * new one.
     */
    public PlaylistManagerInFileImpl()
    {
	selectedIndex = -1;
	loadPlaylists();
	listeners = new HashSet<ListDataListener>();
    }

    /**
     * Tries to load the old playlists from the file system. A new, empty
     * playlists object will be created if an old one could not be loaded.
     */
    @SuppressWarnings("unchecked")
    private void loadPlaylists()
    {
	try
	{
	    final ObjectInputStream objectIS =
		    new ObjectInputStream(new FileInputStream(PLAYLISTS_FILE));
	    final Object input = objectIS.readObject();
	    objectIS.close();
	    playlists = (List<Playlist>) input;

	    // TODO: ugly workaround
	    for (final Playlist playlist : playlists)
	    {
		if (playlist instanceof PlaylistInMemoryImpl)
		{
		    ((PlaylistInMemoryImpl) playlist).postDeserialize();
		}
	    }
	}
	catch (final FileNotFoundException e)
	{
	    playlists = new ArrayList<Playlist>();
	}
	catch (final IOException e)
	{
	    playlists = new ArrayList<Playlist>();
	}
	catch (final ClassNotFoundException e)
	{
	    playlists = new ArrayList<Playlist>();
	}
    }

    /**
     * saves the present playlists object to the file system.
     */
    private void savePlaylists()
    {
	try
	{
	    final ObjectOutputStream objectOS =
		    new ObjectOutputStream(new FileOutputStream(PLAYLISTS_FILE));
	    objectOS.writeObject(playlists);
	    objectOS.close();
	}
	catch (final FileNotFoundException e)
	{
	    Logger.getLogger("de.preamp.clients.java.playlist").log(
		    Level.SEVERE, "Playlists file could not be found", e);
	}
	catch (final IOException e)
	{
	    Logger.getLogger("de.preamp.clients.java.playlist").log(
		    Level.SEVERE, "Playlists could not be saved in file", e);
	}
    }

    /*
     * (non-Javadoc)
     * @see de.preamp.clients.java.playlist.PlaylistManager#getPlaylists()
     */
    @Override
    public final Collection<Playlist> getPlaylists()
    {
	return playlists;
    }

    /*
     * (non-Javadoc)
     * @see
     * de.preamp.clients.java.playlist.PlaylistManager#getSelectedPlaylist()
     */
    @Override
    public final Playlist getSelectedPlaylist()
    {
	final Playlist result;
	if (selectedIndex < playlists.size() && selectedIndex >= 0)
	{
	    result = playlists.get(selectedIndex);
	}
	else
	{
	    result = null;
	}
	return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Iterable#iterator()
     */
    @Override
    public final Iterator<Playlist> iterator()
    {
	return playlists.iterator();
    }

    /*
     * (non-Javadoc)
     * @see
     * javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event
     * .ListSelectionEvent)
     */
    @Override
    public final void valueChanged(final ListSelectionEvent arg0)
    {
	selectedIndex = arg0.getLastIndex();
    }

    /*
     * (non-Javadoc)
     * @see javax.swing.ListModel#addListDataListener(javax.swing.event.
     * ListDataListener)
     */
    @Override
    public final void addListDataListener(final ListDataListener listener)
    {
	listeners.add(listener);
    }

    /*
     * (non-Javadoc)
     * @see javax.swing.ListModel#getElementAt(int)
     */
    @Override
    public final Object getElementAt(final int index)
    {
	return playlists.get(index);
    }

    /*
     * (non-Javadoc)
     * @see javax.swing.ListModel#getSize()
     */
    @Override
    public final int getSize()
    {
	return playlists.size();
    }

    /*
     * (non-Javadoc)
     * @seejavax.swing.ListModel#removeListDataListener(javax.swing.event.
     * ListDataListener)
     */
    @Override
    public final void removeListDataListener(final ListDataListener listener)
    {
	listeners.remove(listener);
    }

    @Override
    public final void newPlaylist(final String name)
    {
	playlists.add(new PlaylistInMemoryImpl(name));
	savePlaylists();
	for (final ListDataListener listener : listeners)
	{
	    listener.contentsChanged(new ListDataEvent(this,
		    ListDataEvent.INTERVAL_ADDED, playlists.size() - 1,
		    playlists.size() - 1));
	}
    }

    @Override
    public final void removePlaylist(final Playlist list)
    {
	final int index = playlists.indexOf(list);
	playlists.remove(list);
	savePlaylists();
	for (final ListDataListener listener : listeners)
	{
	    listener.contentsChanged(new ListDataEvent(this,
		    ListDataEvent.INTERVAL_REMOVED, index, index));
	}
    }
}
